using namespace std;

#include "parser.h"

// TODO: I would love to make this support concatenation without periods
// and I don't think it should be too difficult

// TODO: Make error messages more descriptive.

Parser::Parser(Regex *regex) {
	this->regex = regex;
}

Node *Parser::Parse() {
	if (!bracketsMatch()) {
		cout << "Parse error: brackets mismatch." << endl;
		error = true;
		return NULL;
	}
	else {
		return Expression();
	}
}

Node *Parser::Expression() {
	cout << "In expression" << endl;
	Node *left = Concat();
	
	if (regex->peek() == '|') {
		if (!regex->reachedEnd()) regex->pop();
		else {
			cout << "Parse error." << endl;
			return NULL;
		}
		
		Node *right = Expression();
		Node *node = new Node(UNION, '|', left, right);
		
		return node;
	}
	else return left;
}

Node *Parser::Concat() {
	cout << "In concat" << endl;
	Node *left = Star();
	
	if (regex->peek() == '*' && (!regex->reachedEnd() && prevToken == '*')) {
		cout << "Parse error." << endl;
		error = true;
	}
	
	if (regex->peek() == '.') {
		regex->pop();
		
		Node *right = Concat();
		
		Node *node = new Node(CONCAT, '.', left, right);
		prevToken = '_';
		return node;
	}
	else {
		prevToken = '_';
		return left;
	}
}

Node *Parser::Star() {
	cout << "In star" << endl;
	Node *left = Group();
	
	if (regex->peek() == '*') {
		regex->pop();
		prevToken = '*';
		Node *node = new Node(STAR, '*', left, NULL);
		return node;
	}
	else return left;
}

Node *Parser::Group() {
	cout << "In group" << endl;
	Node *node = NULL;
	
	if (regex->peek() == '(') {
		if (!regex->reachedEnd()) regex->pop();
		else {
			cout << "Parse error." << endl;
			return NULL;
		}
		
		node = Expression();
	
		if (regex->pop() != ')') {
			cout << "Parse error." << endl;
			error = true;
		}
	}
	else node = Character();

	return node; // check this
}

Node *Parser::Character() {
	cout << "In character" << endl;
	char character = regex->peek();
	if (inAlphabet(character)) {
		Node *node = new Node(CHAR, regex->pop(), NULL, NULL);
		return node;
	}
	cout << "Parse error." << endl;
	error = true;
	return NULL;
}


bool Parser::bracketsMatch() {
	string expr = regex->getRegex();
	int count = 0;
	for (int i = 0; i < expr.length(); i++) {
		if (expr[i] == '(') count++;
		if (expr[i] == ')') count--;
	}
	
	if (count != 0) return false;
	else return true;
}

bool Parser::inAlphabet(char character) {
	string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
	size_t found = alphabet.find(character);
	if (found != string::npos) return true;
	else return false;
}

void Parser::print(Node *root) {
	queue<Node*> queue;
	queue.push(root);
	while (!queue.empty()) {
		Node *node = queue.front();
		queue.pop();
		cout << "Node " << node->getToken() << endl;
		if (node->getLeft() != NULL) queue.push(node->getLeft());
		if (node->getRight() != NULL) queue.push(node->getRight());
	}
}

